
/*-------------------------------------------------------------------------
 *
 * archive.c
 *	  前端访问WAL档案的例程
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/fe_utils/archive.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres_fe.h"

#include <unistd.h>
#include <sys/stat.h>

#include "access/xlog_internal.h"
#include "common/archive.h"
#include "common/logging.h"
#include "fe_utils/archive.h"


/*
 * RestoreArchivedFile
 *
 * 尝试从离线归档存储中检索指定文件。
 * 如果成功，返回恢复文件的文件描述符，否则
 * 返回 -1。
 *
 * 对于固定大小的文件，调用者可以将预期大小作为
 * 成功恢复的额外交叉检查。如果文件大小未知，则设置 expectedSize = 0。
 */
int RestoreArchivedFile(const char *fc_path, const char *fc_xlogfname,
					off_t fc_expectedSize, const char *fc_restoreCommand)
{
	char		fc_xlogpath[MAXPGPATH];
	char	   *fc_xlogRestoreCmd;
	int			fc_rc;
	struct stat fc_stat_buf;

	snprintf(fc_xlogpath, MAXPGPATH, "%s/" XLOGDIR "/%s", fc_path, fc_xlogfname);

	fc_xlogRestoreCmd = BuildRestoreCommand(fc_restoreCommand, fc_xlogpath,
										 fc_xlogfname, NULL);
	if (fc_xlogRestoreCmd == NULL)
		pg_fatal("cannot use restore_command with %%r placeholder");

	/*
	 * 执行 restore_command，它应该从
	 * 归档存储中复制缺失的文件。
	 */
	fc_rc = system(fc_xlogRestoreCmd);
	pfree(fc_xlogRestoreCmd);

	if (fc_rc == 0)
	{
		/*
		 * 命令显然成功了，但让我们确保文件
		 * 现在真的存在，并且具有正确的大小。
		 */
		if (stat(fc_xlogpath, &fc_stat_buf) == 0)
		{
			if (fc_expectedSize > 0 && fc_stat_buf.st_size != fc_expectedSize)
				pg_fatal("unexpected file size for \"%s\": %lld instead of %lld",
						 fc_xlogfname, (long long int) fc_stat_buf.st_size,
						 (long long int) fc_expectedSize);
			else
			{
				int			fc_xlogfd = open(fc_xlogpath, O_RDONLY | PG_BINARY, 0);

				if (fc_xlogfd < 0)
					pg_fatal("could not open file \"%s\" restored from archive: %m",
							 fc_xlogpath);
				else
					return fc_xlogfd;
			}
		}
		else
		{
			if (errno != ENOENT)
				pg_fatal("could not stat file \"%s\": %m",
						 fc_xlogpath);
		}
	}

	/*
	 * 如果失败是由于信号引起的，那么返回文件恢复失败
	 * 将会产生误导。因此只需退出并
	 * 退出。诸如“找不到命令”的严重错误也被视为
	 * 致命错误。
	 */
	if (wait_result_is_any_signal(fc_rc, true))
		pg_fatal("restore_command failed: %s",
				 wait_result_to_str(fc_rc));

	/*
	 * 文件不可用，所以让调用者决定接下来该怎么办。
	 */
	pg_log_error("could not restore file \"%s\" from archive",
				 fc_xlogfname);
	return -1;
}
